# Copyright 2010 Giacomo Alzetta
# This file is part of "LimberEditor" and is distribuhited under the
# terms of the MIT license.

'''
limber.viewmanager
==================

This module contains the classes used by the
view managing system.

One exception class is defined here:

-   ViewManagerError

Which is used by the `ViewManager`_ class.

The system is subdived in two classes:
`ViewManager`_ and `ViewDisplayer`_ classes.

ViewManager
-----------

The view manager is responsible for adding and removing the views.
It is also responsible for emitting signals.

This class, in the future, will be responsible for
choosing *how* to show a given view, looking at the
views abilities.

ViewDisplayer
-----------

The ViewDisplayer is not a class, but an API defined
by the AbstractViewDisplayer class.

The class is responsible for showing the views.

A viewmanager might use more than a ViewDisplayer,
for example it might have a Tabbed display
and a Workspace display. If a view has the
right abilities to be added to the
workspace, it will be added to the workspace,
otherwise it will be added in a tab.

The `ViewDisplayer`_ class is defined in the `viewdisplayer` module
'''

from PyQt4 import QtCore


class ViewManagerError(Exception):
    '''Exception raised by the `ViewManager` class.'''

    pass


class ViewManager(QtCore.QObject):
    '''This class is responsible for choosing the ViewDisplayer
    in which the view should be added.
    '''

    def __init__(self, parent, displayer):
        super(ViewManager, self).__init__(parent)

        self._active_window = None
        self._views = []
        self._displayer = displayer

    def number_of_views(self):
        '''Returns the number of views currently handled.'''

        return len(self._views)

    def active_view(self):
        '''Returns the current active window.'''

        return self._active_window

    def add_view(self, view):
        '''Adds a view to the viewmanager.'''

        if view in self._views:
            raise ViewManagerError('The view is already handled '
                                   'by this viewmanager.')
        self._views.append(view)
        self._displayer.add_view(view)
        if self._active_window is None:
            self._active_window = view

    def remove_view(self, view):
        '''Removes the view from the handled views.'''

        try:
            if self._active_window is view:
                index = self._views.index(view)
                if index == 0 and len(self._views) == 1:
                    self._active_window = None
                elif index == 0:
                    self._active_window = self._views[1]
                else:
                    self._active_window = self._views[index - 1]
            self._views.remove(view)
            self._displayer.close_view(view)
        except ValueError:
            raise ViewManagerError('The view is not handled by this manager.')

    def view_parent(self):
        '''Return the object that should be used as parent for *views*.'''

        return self._displayer
